#include "dal/mal/mal.h"
#include "dal/s6b0724/s6b0724_drv.h"

#include "vsprog_ui.h"

#define VSPUI_CONSOLE_EN						1
#define VSPUI_CONSOLE_CFG_LINE_WRAP				1

#if DAL_S6B0724_EN
static struct s6b0724_drv_interface_t s6b0724_ifs =
{
	0,						// uint8_t ebi_port;
	3,						// uint8_t lcd_index;
	0,						// uint32_t cmd_addr;
	0x400					// uint32_t data_addr;
};
static struct s6b0724_drv_param_t s6b0724_param =
{
	{
		{
			8,				// uint8_t data_width;
			EBI_WAIT_NONE,	// enum wait_signal_t wait_signal;
			0,				// uint32_t mux_addr_mask;
		},					// struct ebi_info_t common_info;
		{
			false,			// bool addr_multiplex;
			
			{
				15,			// uint16_t address_setup_cycle_r;
				0,			// uint16_t address_hold_cycle_r;
				255,		// uint16_t data_setup_cycle_r;
				0,			// uint32_t clock_hz_r;
				15,			// uint16_t address_setup_cycle_w;
				0,			// uint16_t address_hold_cycle_w;
				255,		// uint16_t data_setup_cycle_w;
				0,			// uint32_t clock_hz_w;
			}				// struct ebi_sram_psram_nor_timing_t timing;
		}					// struct ebi_sram_psram_nor_param_t param;
	}						// struct ebi_sram_psram_nor_info_t nor_info;
};
static struct mal_info_t s6b0724_mal =
{
	{
		0,					// uint64_t block_size;
		0,					// uint64_t block_number;
	},						// struct mal_capacity_t capacity;
	NULL,					// void *extra;
	0,						// uint32_t erase_page_size;
	0,						// uint32_t write_page_size;
	0,						// uint32_t read_page_size;
	
	&s6b0724_drv,			// const struct mal_driver_t *driver;
};
static struct dal_info_t s6b0724_dal =
{
	&s6b0724_ifs,			// void *ifs;
	&s6b0724_param,			// void *param;
	NULL,					// void *info;
	&s6b0724_mal,			// void *extra;
};

static uint8_t s6b0724_line_buffer[128];

#if VSPUI_CONSOLE_EN
#define CONSOLE_LINE_NUM		5
static uint8_t s6b0724_console_buffer[CONSOLE_LINE_NUM * 128];
static uint32_t console_cur_char = 0;
#endif

#define FONT_SIZE				6
static uint8_t ascii_array[][FONT_SIZE] =
{
	// " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
	{0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
	{0x00,0x5F,0x00,0x00,0x00,0x00},/*"!",1*/
	{0x00,0x03,0x00,0x03,0x00,0x00},/*""",2*/
	{0x14,0x7F,0x14,0x7F,0x14,0x00},/*"#",3*/
	{0x00,0x4C,0x7A,0x4F,0x32,0x00},/*"$",4*/
	{0x00,0x66,0x16,0x68,0x66,0x00},/*"%",5*/
	{0x00,0x38,0x4F,0x4D,0x32,0x00},/*"&",6*/
	{0x00,0x00,0x00,0x03,0x00,0x00},/*"'",7*/
	{0x00,0x00,0x3E,0x41,0x00,0x00},/*"(",8*/
	{0x00,0x00,0x41,0x3E,0x00,0x00},/*")",9*/
	{0x00,0x1C,0x3E,0x1C,0x00,0x00},/*"*",10*/
	{0x00,0x08,0x3E,0x08,0x00,0x00},/*"+",11*/
	{0x00,0x00,0x00,0x60,0x00,0x00},/*",",12*/
	{0x00,0x08,0x08,0x08,0x08,0x00},/*"-",13*/
	{0x00,0x00,0x40,0x00,0x00,0x00},/*".",14*/
	{0x00,0x40,0x30,0x0C,0x03,0x00},/*"/",15*/
	{0x00,0x3E,0x41,0x41,0x3E,0x00},/*"0",16*/
	{0x00,0x42,0x7F,0x40,0x00,0x00},/*"1",17*/
	{0x00,0x62,0x51,0x49,0x46,0x00},/*"2",18*/
	{0x00,0x22,0x49,0x49,0x36,0x00},/*"3",19*/
	{0x00,0x38,0x26,0x7F,0x20,0x00},/*"4",20*/
	{0x00,0x4F,0x49,0x49,0x31,0x00},/*"5",21*/
	{0x00,0x3E,0x49,0x49,0x32,0x00},/*"6",22*/
	{0x00,0x03,0x71,0x09,0x07,0x00},/*"7",23*/
	{0x00,0x36,0x49,0x49,0x36,0x00},/*"8",24*/
	{0x00,0x26,0x49,0x49,0x3E,0x00},/*"9",25*/
	{0x00,0x00,0x24,0x00,0x00,0x00},/*":",26*/
	{0x00,0x40,0x24,0x00,0x00,0x00},/*";",27*/
	{0x00,0x08,0x14,0x22,0x41,0x00},/*"<",28*/
	{0x00,0x14,0x14,0x14,0x14,0x00},/*"=",29*/
	{0x00,0x41,0x22,0x14,0x08,0x00},/*">",30*/
	{0x00,0x02,0x51,0x09,0x06,0x00},/*"?",31*/
	{0x00,0x0E,0x71,0x49,0x7E,0x00},/*"@",32*/
	{0x00,0x7E,0x11,0x11,0x7E,0x00},/*"A",33*/
	{0x00,0x7F,0x49,0x49,0x36,0x00},/*"B",34*/
	{0x00,0x3E,0x41,0x41,0x22,0x00},/*"C",35*/
	{0x00,0x7F,0x41,0x41,0x3E,0x00},/*"D",36*/
	{0x00,0x7F,0x49,0x49,0x41,0x00},/*"E",37*/
	{0x00,0x7F,0x09,0x09,0x01,0x00},/*"F",38*/
	{0x00,0x3E,0x41,0x49,0x3A,0x00},/*"G",39*/
	{0x00,0x7F,0x08,0x08,0x7F,0x00},/*"H",40*/
	{0x00,0x41,0x7F,0x41,0x00,0x00},/*"I",41*/
	{0x00,0x30,0x40,0x40,0x3F,0x00},/*"J",42*/
	{0x00,0x7F,0x08,0x14,0x63,0x00},/*"K",43*/
	{0x00,0x7F,0x40,0x40,0x40,0x00},/*"L",44*/
	{0x00,0x7F,0x06,0x06,0x7F,0x00},/*"M",45*/
	{0x00,0x7F,0x06,0x18,0x7F,0x00},/*"N",46*/
	{0x00,0x7F,0x41,0x41,0x7F,0x00},/*"O",47*/
	{0x00,0x7F,0x09,0x09,0x06,0x00},/*"P",48*/
	{0x00,0x3E,0x51,0x61,0x7E,0x00},/*"Q",49*/
	{0x00,0x7F,0x19,0x29,0x46,0x00},/*"R",50*/
	{0x00,0x26,0x49,0x49,0x32,0x00},/*"S",51*/
	{0x00,0x01,0x7F,0x01,0x01,0x00},/*"T",52*/
	{0x00,0x3F,0x40,0x40,0x3F,0x00},/*"U",53*/
	{0x00,0x0F,0x70,0x70,0x0F,0x00},/*"V",54*/
	{0x00,0x7F,0x30,0x30,0x7F,0x00},/*"W",55*/
	{0x00,0x63,0x1C,0x1C,0x63,0x00},/*"X",56*/
	{0x03,0x04,0x78,0x04,0x03,0x00},/*"Y",57*/
	{0x00,0x61,0x59,0x4D,0x43,0x00},/*"Z",58*/
	{0x00,0x00,0x7F,0x41,0x00,0x00},/*"[",59*/
	{0x03,0x0C,0x30,0x40,0x00,0x00},/*"\",60*/
	{0x00,0x00,0x41,0x7F,0x00,0x00},/*"]",61*/
	{0x00,0x02,0x01,0x02,0x00,0x00},/*"^",62*/
	{0x00,0x40,0x40,0x40,0x40,0x00},/*"_",63*/
	{0x00,0x00,0x03,0x00,0x00,0x00},/*"`",64*/
	{0x00,0x20,0x58,0x58,0x78,0x00},/*"a",65*/
	{0x00,0x7F,0x48,0x48,0x30,0x00},/*"b",66*/
	{0x00,0x30,0x48,0x48,0x48,0x00},/*"c",67*/
	{0x00,0x30,0x48,0x48,0x7F,0x00},/*"d",68*/
	{0x00,0x30,0x58,0x58,0x10,0x00},/*"e",69*/
	{0x00,0x08,0x7C,0x0A,0x08,0x00},/*"f",70*/
	{0x00,0x10,0xA8,0xA8,0x78,0x00},/*"g",71*/
	{0x00,0x7F,0x08,0x78,0x00,0x00},/*"h",72*/
	{0x00,0x00,0x74,0x00,0x00,0x00},/*"i",73*/
	{0x00,0x80,0x80,0x74,0x00,0x00},/*"j",74*/
	{0x00,0x7F,0x10,0x28,0x48,0x00},/*"k",75*/
	{0x00,0x40,0x7F,0x40,0x00,0x00},/*"l",76*/
	{0x00,0x78,0x08,0x78,0x78,0x00},/*"m",77*/
	{0x00,0x78,0x08,0x08,0x70,0x00},/*"n",78*/
	{0x00,0x30,0x48,0x48,0x30,0x00},/*"o",79*/
	{0x00,0xF8,0x48,0x48,0x30,0x00},/*"p",80*/
	{0x00,0x30,0x48,0x48,0xF8,0x00},/*"q",81*/
	{0x00,0x78,0x10,0x08,0x08,0x00},/*"r",82*/
	{0x00,0x50,0x58,0x68,0x28,0x00},/*"s",83*/
	{0x00,0x08,0x7C,0x48,0x00,0x00},/*"t",84*/
	{0x00,0x38,0x40,0x40,0x78,0x00},/*"u",85*/
	{0x00,0x18,0x60,0x60,0x18,0x00},/*"v",86*/
	{0x18,0x60,0x38,0x60,0x18,0x00},/*"w",87*/
	{0x00,0x48,0x30,0x30,0x48,0x00},/*"x",88*/
	{0x00,0x18,0xA0,0xA0,0x78,0x00},/*"y",89*/
	{0x00,0x48,0x68,0x58,0x48,0x00},/*"z",90*/
	{0x00,0x08,0x77,0x41,0x00,0x00},/*"{",91*/
	{0x00,0x00,0x7F,0x00,0x00,0x00},/*"|",92*/
	{0x00,0x41,0x77,0x08,0x00,0x00},/*"}",93*/
	{0x00,0x02,0x01,0x02,0x01,0x00},/*"~",94*/
	{0x00,0x00,0x00,0x00,0x00,0x00},/*" ",95*/
};

static void vsprog_ui_set_string_to_buffer(uint8_t *buffer, char *str)
{
	uint64_t bs = s6b0724_mal.capacity.block_size;
	uint16_t i, max = min(strlen(str), bs / FONT_SIZE);
	
	if (buffer != NULL)
	{
		memset(buffer, 0, bs);
		if (str != NULL)
		{
			for (i = 0; i < max; i++)
			{
				if ((str[i] < ' ') || (str[i] > (' ' + dimof(ascii_array))))
				{
					memset(buffer, 0, FONT_SIZE);
				}
				else
				{
					memcpy(buffer, ascii_array[str[i] - ' '], FONT_SIZE);
				}
				buffer += FONT_SIZE;
			}
		}
	}
}

static vsf_err_t vsprog_ui_set_string(uint8_t block, char *str)
{
	vsprog_ui_set_string_to_buffer(s6b0724_line_buffer, str);
	return mal.writeblock(&s6b0724_dal, block * s6b0724_mal.capacity.block_size,
							s6b0724_line_buffer, 1);
}
#endif		// #if DAL_S6B0724_EN

vsf_err_t vsprog_ui_init(void)
{
#if DAL_S6B0724_EN
	uint64_t i;
	
#if VSPUI_CONSOLE_EN
	console_cur_char = 0;
	memset(s6b0724_console_buffer, 0, sizeof(s6b0724_console_buffer));
#endif
	memset(s6b0724_line_buffer, 0, sizeof(s6b0724_line_buffer));
	
	mal.init(&s6b0724_dal);
	for (i = 0; i < s6b0724_mal.capacity.block_number; i++)
	{
		mal.writeblock(&s6b0724_dal, i * s6b0724_mal.capacity.block_size,
						s6b0724_line_buffer, 1);
	}
#endif
	return VSFERR_NONE;
}

vsf_err_t vsprog_ui_fini(void)
{
#if DAL_S6B0724_EN
	return mal.fini(&s6b0724_dal);
#else
	return VSFERR_NONE;
#endif
}

vsf_err_t vsprog_ui_set_title(char *title)
{
#if DAL_S6B0724_EN
	return vsprog_ui_set_string(0, title);
#else
	return VSFERR_NONE;
#endif
}

vsf_err_t vsprog_ui_print(char *str)
{
#if DAL_S6B0724_EN && VSPUI_CONSOLE_EN
	uint64_t i, bs = s6b0724_mal.capacity.block_size;
	uint8_t *base = &s6b0724_console_buffer[(CONSOLE_LINE_NUM - 1) * bs];
	uint8_t *cur_ptr;
	
	if (NULL == str)
	{
		return VSFERR_NONE;
	}
	
	while (str[0] != '\0')
	{
		if (str[0] == '\n')
		{
			// new line
			memcpy(&s6b0724_console_buffer[0], &s6b0724_console_buffer[bs],
					(CONSOLE_LINE_NUM - 1) * bs);
			memset(base, 0, bs);
			console_cur_char = 0;
		}
		else if (str[0] == '\r')
		{
			// return
			console_cur_char = 0;
		}
		else if (str[0] == '\b')
		{
			if (console_cur_char > 0)
			{
				console_cur_char--;
			}
		}
		else
		{
#if VSPUI_CONSOLE_CFG_LINE_WRAP
			if (console_cur_char >= (bs / FONT_SIZE))
			{
				// new line
				memcpy(&s6b0724_console_buffer[0], &s6b0724_console_buffer[bs],
						(CONSOLE_LINE_NUM - 1) * bs);
				memset(base, 0, bs);
				console_cur_char = 0;
			}
#endif
			if (console_cur_char < (bs / FONT_SIZE))
			{
				cur_ptr = base + console_cur_char * FONT_SIZE;
				if ((str[0] < ' ') || (str[0] >= (' ' + dimof(ascii_array))))
				{
					memset(cur_ptr, 0, FONT_SIZE);
				}
				else
				{
					memcpy(cur_ptr, ascii_array[str[0] - ' '], FONT_SIZE);
				}
			}
			console_cur_char++;
		}
		str++;
	}
	
	for (i = 0; i < CONSOLE_LINE_NUM; i++)
	{
		mal.writeblock(&s6b0724_dal, (i + 1) * bs,
						&s6b0724_console_buffer[i * bs], 1);
	}
#endif
	return VSFERR_NONE;
}

vsf_err_t vsprog_ui_set_task(char *task)
{
#if DAL_S6B0724_EN
	return vsprog_ui_set_string(6, task);
#else
	return VSFERR_NONE;
#endif
}

vsf_err_t vsprog_ui_set_progress(uint8_t percentage)
{
#if DAL_S6B0724_EN
	uint64_t bs = s6b0724_mal.capacity.block_size;
	uint64_t bytes = min(percentage * bs / 100, bs), i = 0;
	
	while (i++ < bytes)
	{
		s6b0724_line_buffer[i] = 0xFF;
	}
	while (i++ < bs)
	{
		s6b0724_line_buffer[i] = 0x00;
	}
	return mal.writeblock(&s6b0724_dal, 7 * bs, s6b0724_line_buffer, 1);
#else
	return VSFERR_NONE;
#endif
}
